home *** CD-ROM | disk | FTP | other *** search
/ Acorn User: China / Acorn User China CD-ROM (UK) (Disc A) / Acorn User China CD-ROM (UK) (Disc A).bin / DEMON / MISC / NETLITE2.ARC / NET / c / UDP < prev    next >
Encoding:
Text File  |  1993-04-03  |  8.3 KB  |  282 lines

  1. /* Send and receive User Datagram Protocol packets */
  2. #include <stdlib.h>
  3. #include <string.h>
  4. #include "global.h"
  5. #include "mbuf.h"
  6. #include "misc.h"
  7. #include "netuser.h"
  8. #include "internet.h"
  9. #include "udp.h"
  10.  
  11. static struct udp_cb *lookup_udp(struct socket *);
  12. static int16 hash_udp(struct socket *);
  13.  
  14. /* Hash table for UDP structures */
  15. struct udp_cb *udps[NUDP] = { NULLUDP} ;
  16. struct udp_stat udp_stat;       /* Statistics */
  17.  
  18. /* Create a UDP control block for lsocket, so that we can queue
  19.  * incoming datagrams.
  20.  */
  21. int open_udp(struct socket *lsocket, void (*r_upcall)(), void *arg)
  22. {
  23.         register struct udp_cb *up;
  24.         int16 hval;
  25.  
  26.         if((up = lookup_udp(lsocket)) != NULLUDP)
  27.                 return 0;       /* Already exists */
  28.         if((up = (struct udp_cb *)malloc(sizeof(struct udp_cb))) == NULLUDP){
  29.                 net_error = NO_SPACE;
  30.                 return -1;
  31.         }
  32.         up->rcvq           = NULLBUF;
  33.         up->rcvcnt         = 0;
  34.         up->socket.address = lsocket->address;
  35.         up->socket.port    = lsocket->port;
  36.         up->r_upcall       = r_upcall;
  37.         up->arg            = arg;
  38.  
  39.         hval = hash_udp(lsocket);
  40.         up->next = udps[hval];
  41.         up->prev = NULLUDP;
  42.         if(up->next != NULLUDP)
  43.                 up->next->prev = up;
  44.         udps[hval] = up;
  45.         return 0;
  46. }
  47.  
  48. /* Send a UDP datagram */
  49. int send_udp(struct socket *lsocket, struct socket *fsocket,
  50.              char tos, char ttl, struct mbuf *data,
  51.              int16 length, int16 id, char df)
  52. {
  53.         struct mbuf *bp;
  54.         struct pseudo_header ph;
  55.         struct udp udp;
  56.  
  57.         length = UDPHDR;
  58.         if(data != NULLBUF)
  59.                 length += len_mbuf(data);
  60.  
  61.         udp.source = lsocket->port;
  62.         udp.dest   = fsocket->port;
  63.         udp.length = length;
  64.  
  65.         /* Create IP pseudo-header, compute checksum and send it */
  66.         ph.length   = length;
  67.         ph.source   = lsocket->address;
  68.         ph.dest     = fsocket->address;
  69.         ph.protocol = UDP_PTCL;
  70.  
  71.         if((bp = htonudp(&udp,data,&ph)) == NULLBUF){
  72.                 net_error = NO_SPACE;
  73.                 free_p(data);
  74.                 return 0;
  75.         }
  76.         udp_stat.sent++;
  77.         ip_send(lsocket->address,fsocket->address,UDP_PTCL,tos,ttl,bp,length,id,df);
  78.         return length;
  79. }
  80.  
  81. /* Accept a waiting datagram, if available. Returns length of datagram */
  82. int recv_udp(struct socket *lsocket, struct socket *fsocket, struct mbuf **bp)
  83. {
  84.         register struct udp_cb *up;
  85.         struct socket *sp;
  86.         struct mbuf *buf;
  87.         int16 length;
  88.  
  89.  
  90.         up = lookup_udp(lsocket);
  91.         if(up == NULLUDP){
  92.                 net_error = NO_CONN;
  93.                 return -1;
  94.         }
  95.         if(up->rcvcnt == 0){
  96.                 net_error = WOULDBLK;
  97.                 return -1;
  98.         }
  99.         buf = dequeue(&up->rcvq);
  100.         up->rcvcnt--;
  101.  
  102.         sp = (struct socket *)buf->data;
  103.         /* Fill in the user's foreign socket structure, if given */
  104.         if(fsocket != NULLSOCK){
  105.                 fsocket->address = sp->address;
  106.                 fsocket->port    = sp->port;
  107.         }
  108.         /* Strip socket header and hand data to user */
  109.         pullup(&buf,NULLCHAR,sizeof(struct socket));
  110.         length = len_mbuf(buf);
  111.         if(bp != (struct mbuf **)NULL)
  112.                 *bp = buf;
  113.         else
  114.                 free_p(buf);
  115.         return length;
  116. }
  117. /* Delete a UDP control block */
  118. int del_udp(struct socket *lsocket)
  119. {
  120.         register struct udp_cb *up;
  121.         struct mbuf *bp;
  122.         int16 hval;
  123.  
  124.         if((up = lookup_udp(lsocket)) == NULLUDP){
  125.                 net_error = INVALID;
  126.                 return -1;
  127.         }               
  128.         /* Get rid of any pending packets */
  129.         while(up->rcvcnt != 0){
  130.                 bp = up->rcvq;
  131.                 up->rcvq = up->rcvq->anext;
  132.                 free_p(bp);
  133.                 up->rcvcnt--;
  134.         }
  135.         hval = hash_udp(&up->socket);
  136.         if(udps[hval] == up){
  137.                 /* First on list */
  138.                 udps[hval] = up->next;
  139.                 up->next->prev = NULLUDP;
  140.         } else {
  141.                 up->prev->next = up->next;
  142.                 up->next->prev = up->prev;
  143.         }
  144.         free((char *)up);
  145.         return 0;
  146. }
  147. /* Process an incoming UDP datagram */
  148. void udp_input(struct mbuf *bp, char protocol, int32 source,
  149.                int32 dest, char tos, int16 length, char rxbroadcast)
  150. {
  151.         struct pseudo_header ph;
  152.         struct udp udp;
  153.         struct udp_cb *up;
  154.         struct socket lsocket;
  155.         struct socket *fsocket;
  156.         struct mbuf *packet;
  157.         int ckfail = 0;
  158.  
  159.         tos = tos;
  160.  
  161.         if(bp == NULLBUF)
  162.                 return;
  163.  
  164.         udp_stat.rcvd++;
  165.  
  166.         /* Create pseudo-header and verify checksum */
  167.         ph.source = source;
  168.         ph.dest = dest;
  169.         ph.protocol = protocol;
  170.         ph.length = length;
  171.  
  172.         if(cksum(&ph,bp,length) != 0)
  173.                 /* Checksum apparently failed, note for later */
  174.                 ckfail++;
  175.  
  176.         /* Extract UDP header in host order */
  177.         ntohudp(&udp,&bp);
  178.  
  179.         /* If the checksum field is zero, then ignore a checksum error.
  180.          * I think this is dangerously wrong, but it is in the spec.
  181.          */
  182.         if(ckfail && udp.checksum != 0){
  183.                 udp_stat.cksum++;
  184.                 free_p(bp);
  185.                 return;
  186.         }
  187.         /* If this was a broadcast packet, pretend it was sent to us */
  188.         if(rxbroadcast){
  189.                 lsocket.address = ip_addr;
  190.                 udp_stat.bdcsts++;
  191.         } else
  192.                 lsocket.address = dest;
  193.  
  194.         lsocket.port = udp.dest;
  195.         /* See if there's somebody around to read it */
  196.         if((up = lookup_udp(&lsocket)) == NULLUDP){
  197.                 /* Nope, toss it on the floor */
  198.                 udp_stat.unknown++;
  199.                 free_p(bp);
  200.                 return;
  201.         }
  202.         /* Create space for the foreign socket info */
  203.         if((packet = pushdown(bp,sizeof(struct socket))) == NULLBUF){
  204.                 /* No space, drop whole packet */
  205.                 free_p(bp);
  206.                 return;
  207.         }
  208.         fsocket = (struct socket *)packet->data;
  209.         fsocket->address = source;
  210.         fsocket->port = udp.source;
  211.  
  212.         /* Queue it */
  213.         enqueue(&up->rcvq,packet);
  214.         up->rcvcnt++;
  215.         if(up->r_upcall)
  216.                 (*up->r_upcall)(&lsocket,up->rcvcnt,up->arg);
  217. }
  218. /* Look up UDP socket, return control block pointer or NULLUDP if nonexistant */
  219. static struct udp_cb *lookup_udp(struct socket *socket)
  220. {
  221.         register struct udp_cb *up;
  222.  
  223.         up = udps[hash_udp(socket)];
  224.  
  225.         while (up != NULLUDP) {
  226.                 if (socket->address == up->socket.address &&
  227.                     socket->port    == up->socket.port)
  228.                         break;
  229.  
  230.                 up = up->next;
  231.         }
  232.         return up;
  233. }
  234.  
  235. /* Hash a UDP socket (address and port) structure */
  236. static int16 hash_udp(struct socket *socket)
  237. {
  238.         int16 hval;
  239.  
  240.         /* Compute hash function on socket structure */
  241.         hval = hiword(socket->address);
  242.         hval ^= loword(socket->address);
  243.         hval ^= socket->port;
  244.         hval %= NUDP;
  245.         return hval;
  246. }
  247. /* Convert UDP header in internal format to an mbuf in external format */
  248. struct mbuf *htonudp(struct udp *udp, struct mbuf *data, struct pseudo_header *ph)
  249. {
  250.         struct mbuf *bp;
  251.         register char *cp;
  252.         int16 checksum;
  253.  
  254.         /* Allocate UDP protocol header and fill it in */
  255.         if((bp = pushdown(data,UDPHDR)) == NULLBUF)
  256.                 return NULLBUF;
  257.  
  258.         cp = bp->data;
  259.         cp = put16(cp,udp->source);     /* Source port */
  260.         cp = put16(cp,udp->dest);       /* Destination port */
  261.         cp = put16(cp,udp->length);     /* Length */
  262.         *cp++ = 0;                      /* Clear checksum */
  263.         *cp-- = 0;
  264.  
  265.         /* All zeros and all ones is equivalent in one's complement arithmetic;
  266.          * the spec requires us to change zeros into ones to distinguish an
  267.          * all-zero checksum from no checksum at all
  268.          */
  269.         if((checksum = cksum(ph,bp,ph->length)) == 0)
  270.                 checksum = (int16)0xffffffff;
  271.         put16(cp,checksum);
  272.         return bp;
  273. }
  274. /* Convert UDP header in mbuf to internal structure */
  275. void ntohudp(struct udp *udp, struct mbuf **bpp)
  276. {
  277.         udp->source = pull16(bpp);
  278.         udp->dest = pull16(bpp);
  279.         udp->length = pull16(bpp);
  280.         udp->checksum = pull16(bpp);
  281. }
  282.